package com.chat.netty.websocketserver.websocketHandler;


import com.alibaba.fastjson.JSONObject;
import com.chat.netty.websocketserver.service.ChatService;
import com.chat.netty.websocketserver.vo.NettyConstant;
import com.chat.netty.websocketserver.vo.ResultMsg;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.thymeleaf.util.StringUtils;

import javax.annotation.Resource;


@Component
@Sharable
public class WebsocketNettyServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketNettyServerHandler.class);

    @Resource
    private ChatService chatService;

    /**
     * 描述：读取完连接的消息后，对消息进行处理。
     *      这里主要是处理WebSocket请求
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) {
        handlerWebSocketFrame(ctx, msg);
    }

    /**
     * 描述：处理WebSocketFrame
     * @param ctx
     * @param frame
     * @throws Exception
     */
    private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
        // 关闭请求
        if (frame instanceof CloseWebSocketFrame) {
            WebSocketServerHandshaker handshaker =
                    NettyConstant.webSocketHandshakerMap.get(ctx.channel().id().asLongText());
            if (handshaker == null) {
                sendErrorMessage(ctx, "不存在的客户端连接！");
            } else {
                handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            }
            return;
        }
        // ping请求
        if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        // 只支持文本格式，不支持二进制消息
        if (!(frame instanceof TextWebSocketFrame)) {
            sendErrorMessage(ctx, "仅支持文本(Text)格式，不支持二进制消息");
        }

        // 客服端发送过来的消息
        String request = ((TextWebSocketFrame)frame).text();
        LOGGER.info("服务端收到新信息：" + request);
        JSONObject param = null;
        try {
            param = JSONObject.parseObject(request);
        } catch (Exception e) {
            sendErrorMessage(ctx, "JSON字符串转换出错！");
            e.printStackTrace();
        }

        if (param != null){
            //存在userid和groupid  则注册到组
            if (Boolean.parseBoolean((String)param.get("register"))){
                if (!StringUtils.isEmpty((String) param.get("groupId"))){
                    chatService.registerGroup(param,ctx);
                    return;
                }
                chatService.register(param, ctx);
                return;
            }


            if (!StringUtils.isEmpty((String) param.get("msg")) && !ObjectUtils.isEmpty(param.get("type"))){
                Integer type = (Integer) param.get("type");
                if (type == 1){//全部
                  chatService.pushMsgToAll(param);
                }
                if (type == 2){ // 指定聊天
                  chatService.pushMsgToOther(param);
                }
                if (type == 3){ // 群聊
                    chatService.pushMsgToGroup(param);
                }
            }
        }

    }

    /**
     * 描述：客户端断开连接
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        chatService.remove(ctx);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 添加到channelGroup 通道组
        chatService.add(ctx);
    }

    /**
     * 异常处理：关闭channel
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }


    private void sendErrorMessage(ChannelHandlerContext ctx, String errorMsg) {
        String responseJson =  new ResultMsg().error(errorMsg);
        ctx.channel().writeAndFlush(new TextWebSocketFrame(responseJson));
    }

}
